package com.easyCode.sqlBuilder.oop;

import com.easyCode.sqlBuilder.sqlInfo.BaseDataBaseSqlInfo;
import com.easyCode.sqlBuilder.sqlInfo.BaseFiledSqlInfo;
import com.easyCode.sqlBuilder.sqlInfo.BaseKeySqlInfo;
import com.easyCode.sqlBuilder.sqlInfo.BaseTableSqlInfo;
import com.easyCode.sqlManager.MappingContainer;
import com.easyCode.util.ReflectionUtils;
import com.easyCode.util.StringUtil;
import lombok.Data;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;


/**
 * 负责处理对象到sqlInfo之间的映射过程
 * @author 大忽悠
 * @create 2022/12/8 20:38
 */
@Data
public class OopMapper {
    /**
     * 映射对象列表路径
     */
    private List<Object> mapperObjList=new ArrayList<>();

    /**
     * 解析相关对象,然后填充数据库信息
     */
    public void mapper(BaseDataBaseSqlInfo dataBaseSqlInfo) {
         mapperObjList.forEach(obj->{dataBaseSqlInfo.addTableSqlInfo(doMapper(obj));});
    }

    private BaseTableSqlInfo doMapper(Object obj) {
        List<BaseFiledSqlInfo> baseFiledSqlInfoList = new ArrayList<>();
        List<BaseKeySqlInfo> keySqlInfoList=new ArrayList<>();
        parseFieldsAndKeys(baseFiledSqlInfoList,keySqlInfoList,obj);
        BaseTableSqlInfo tableSqlInfo = parseTable(obj);
        tableSqlInfo.addFiled(baseFiledSqlInfoList.toArray(new BaseFiledSqlInfo[]{}));
        tableSqlInfo.addKey(keySqlInfoList.toArray(new BaseKeySqlInfo[]{}));
        return tableSqlInfo;
    }

    private void parseFieldsAndKeys(List<BaseFiledSqlInfo> baseFiledSqlInfoList, List<BaseKeySqlInfo> keySqlInfoList, Object obj) {
        doParse(ReflectionUtils.getAllDeclaredFileds(obj.getClass()), baseFiledSqlInfoList,keySqlInfoList);
    }

    private void doParse(List<Field> fields, List<BaseFiledSqlInfo> baseFiledSqlInfoList, List<BaseKeySqlInfo> keySqlInfoList) {
        fields.forEach(field -> {
            BaseFiledSqlInfo baseFiledSqlInfo = doBuildFiledSqlInfo(field);
            BaseKeySqlInfo keySqlInfo = doBuildKeySqlInfo(field, baseFiledSqlInfo);
            baseFiledSqlInfoList.add(baseFiledSqlInfo);
            if(keySqlInfo!=null){
                keySqlInfoList.add(keySqlInfo);
            }
        });
    }


    private BaseKeySqlInfo doBuildKeySqlInfo(Field field, BaseFiledSqlInfo baseFiledSqlInfo) {
        Key key = field.getAnnotation(Key.class);
        if(key==null){
            return null;
        }
        BaseKeySqlInfo baseKeySqlInfo= (BaseKeySqlInfo) MappingContainer.getSqlInfo(BaseKeySqlInfo.class);
        baseKeySqlInfo.setKeyName(key.keyName());
        baseKeySqlInfo.setKeyType(key.keyType());

        //优先考虑外键情况,如果指定了masterTableName,那么忽略普通索引情况
        String masterTableName = key.masterTableName();
        //普通索引
        if(StringUtil.isNullOrEmpty(masterTableName)){
            List<String> columns=new ArrayList<>();
            columns.add(baseFiledSqlInfo.getFiledName());
            columns.addAll(List.of(key.otherColumns()));
            baseKeySqlInfo.addColumn(columns.toArray(new String[]{}));
        }else {
            //外键情况
            baseKeySqlInfo.setMasterTableName(masterTableName);

            List<String> salveColumns=new ArrayList<>();
            salveColumns.add(baseFiledSqlInfo.getFiledName());
            salveColumns.addAll(List.of(key.otherSalveColumns()));
            baseKeySqlInfo.addSalveColumn(salveColumns.toArray(new String[]{}));
            baseKeySqlInfo.addMasterColumn(key.masterColumns());
        }
        return baseKeySqlInfo;
    }

    private BaseTableSqlInfo parseTable(Object obj) {
        BaseTableSqlInfo baseTableSqlInfo = (BaseTableSqlInfo) MappingContainer.getSqlInfo(BaseTableSqlInfo.class);
        //没有设置表名时,表名默认为类名小写转驼峰
        baseTableSqlInfo.setTableName(StringUtil.camelToUnderline(obj.getClass().getSimpleName()));
        Table table = obj.getClass().getAnnotation(Table.class);
        if(table==null){
            return baseTableSqlInfo;
        }
        baseTableSqlInfo.setDropTable(table.dropTable());
        baseTableSqlInfo.setComment(table.comment());
        if(!StringUtil.isNullOrEmpty(table.value())){
            baseTableSqlInfo.setTableName(table.value());
        }
        return baseTableSqlInfo;
    }

    private BaseFiledSqlInfo doBuildFiledSqlInfo(Field field) {
        //1.先构建出一个默认的FiledSqlInfo,在根据相关注解进行信息覆盖
        BaseFiledSqlInfo baseFiledSqlInfo = (BaseFiledSqlInfo) MappingContainer.getSqlInfo(BaseFiledSqlInfo.class);
        //字段名也是默认转驼峰,除非手动指定
        baseFiledSqlInfo.setFiledName(StringUtil.camelToUnderline(field.getName()));
        baseFiledSqlInfo.setFiledType(MappingContainer.getMysqlType(field.getType()));
        baseFiledSqlInfo.setOrder(Integer.MAX_VALUE);
        baseFiledSqlInfo.setFiledLen(MappingContainer.getDefaultLen(field.getType()));

        //2.根据注解信息覆盖默认值
        Filed filed = field.getAnnotation(Filed.class);
        if(filed==null){
            return baseFiledSqlInfo;
        }
        //字段名
        if(!StringUtil.isNullOrEmpty(filed.value())){
            baseFiledSqlInfo.setFiledName(filed.value());
        }
        //字段长度
        if(!StringUtil.isNullOrEmpty(filed.filedLen())){
            baseFiledSqlInfo.setFiledLen(filed.filedLen());
        }
        //字段类型
        if(!StringUtil.isNullOrEmpty(filed.filedType())){
            baseFiledSqlInfo.setFiledType(filed.filedType());
        }
        baseFiledSqlInfo.setComment(filed.comment());
        baseFiledSqlInfo.setDefaultVal(filed.defaultVal());
        baseFiledSqlInfo.setNotNull(filed.notNull());
        baseFiledSqlInfo.setAutoIncrement(filed.autoIncrement());
        baseFiledSqlInfo.setOrder(filed.order());
        return baseFiledSqlInfo;
    }

    public void addMapperObj(Object... objList) {
        mapperObjList.addAll(List.of(objList));
    }
}
